package com.yuntsg.ruiijn.databse_search.service;

import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.ds.DSFactory;
import cn.hutool.http.HttpUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.FieldAndFormat;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.HighlightField;
import co.elastic.clients.elasticsearch.core.search.HighlighterType;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.alibaba.fastjson.JSONObject;
import com.yuntsg.ruiijn.paperana.entity.BackMatchEntity;
import com.yuntsg.ruiijn.paperana.entity.PmUtEntity;
import com.yuntsg.ruiijn.paperana.utils.DbSearchUtil;
import com.yuntsg.ruiijn.paperana.utils.esutils.EsServerEntity;
import com.yuntsg.ruiijn.paperana.utils.esutils.IndexConfig;
import common.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Author: gcr
 * @Date: 2023/10/11 18:55
 */
@Service
@SuppressWarnings("all")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class EsWebService {


    private final ElasticsearchClient esClient;

    @Value("${central.api.url}")
    public String escenterUrl;

    // 这个项目进行es 对外服务 所有的地址采用post 请求加data和  code返回模式 所有es 公共库建设的都走这里  自建库走自己机器

    // 这个是中央服务器模式 对外返回数据
    @SneakyThrows
    /**
     * @param type 查询类型 1 全网查询 2 我的自定义查询
     * @param source 来源
     * @param page 页码
     * @param content 查询字符
     * @return
     */
    public List<Object> esBackData(Integer type, Integer source, Integer page, String content) {
        Integer code = 0;
        String msg = "";
        List<Object> res = new ArrayList<>();
        // type ==1 全网检索返回前5条

        if (type == 1) {
            // 走全网检索返回数据 检索返回数据
            if (source == 1) {
                SearchResponse<JSONObject> response = esClient.search(s -> s
                                .index(IndexConfig.PUB_TEXT_INDEX)
                                .fields(Arrays.asList(FieldAndFormat.of(builder -> builder.field("file_id")),
                                        FieldAndFormat.of(builder -> builder.field("sentence")),
                                        FieldAndFormat.of(builder -> builder.field("database_type")),
                                        FieldAndFormat.of(builder -> builder.field("str")),
                                        FieldAndFormat.of(builder -> builder.field("sub_project")),
                                        FieldAndFormat.of(builder -> builder.field("table_id"))))
                                .from((page - 1) * 5)
                                .size(5)
                                .highlight(h -> h
                                        .fields("str", HighlightField.of(j -> j.type(HighlighterType.Unified)
                                                .fragmentSize(10)
                                                .numberOfFragments(0)))
                                )
                                .query(q -> q.multiMatch(t -> t
                                                .slop(3)
                                                .fields(Arrays.asList("str"))
                                                .query(content)
                                                .minimumShouldMatch("80%")
                                        )
                                ),
                        JSONObject.class
                );
                List<Hit<JSONObject>> hits = response.hits().hits();
                //
                for (Hit<JSONObject> hit : hits) {

                }
                res = Collections.singletonList(response.hits().hits());
            } else {
                SearchResponse<JSONObject> response = esClient.search(s -> s
                                .index(IndexConfig.PUB_TEXT_INDEX)
                                .fields(Arrays.asList(
                                        FieldAndFormat.of(builder -> builder.field("file_id")),
                                        FieldAndFormat.of(builder -> builder.field("paragraph_name")),
                                        FieldAndFormat.of(builder -> builder.field("sentence")),
                                        FieldAndFormat.of(builder -> builder.field("database_type")),
                                        FieldAndFormat.of(builder -> builder.field("str")),
                                        FieldAndFormat.of(builder -> builder.field("sub_project")),
                                        FieldAndFormat.of(builder -> builder.field("table_id"))))
                                .from((page - 1) * 5)
                                .size(5)
                                .highlight(h -> h
                                        .fields("str", HighlightField.of(j -> j.type(HighlighterType.Unified)
                                                .fragmentSize(10)
                                                .numberOfFragments(0)))
                                )
                                .query(q -> q.matchPhrase
                                        (t -> t
                                                .slop(3)
                                                .field("str")
                                                .query(content)

                                        )
                                ),
                        JSONObject.class
                );
                List<Hit<JSONObject>> hits = response.hits().hits();
                //
                for (Hit<JSONObject> hit : hits) {
                    // es id
                    String id = hit.id();
                    // es 高亮内容
                    Map<String, List<String>> highlight = hit.highlight();
                    // es fields
                    Map<String, JsonData> fields = hit.fields();
                    // es 得分
                    Double score = hit.score();
                    // es 字段内容 和fields 类似 只是把类型都给你归类好了
                    JSONObject source1 = hit.source();
                    EsServerEntity esServerEntity = new EsServerEntity();
                    esServerEntity.setESid(id);
                    esServerEntity.setHighlight(highlight);
                    Map<String, String[]> fieldsNew = new HashMap<>();
                    if (fields != null) {
                        fields.forEach((k, v) -> {
                            String[] str = new String[]{v.to(String[].class)[0]};
                            fieldsNew.put(k, str);
                        });
                    }

                    esServerEntity.setFields(fieldsNew);
                    esServerEntity.setScore(score);
                    esServerEntity.setSource(source1);
                    res.add(esServerEntity);
                }
            }
            // 进行转换可以前台可以看的数据
            return res;
        }
        if (type == 2) {
            BoolQuery.Builder allQueryBuilder = new BoolQuery.Builder();
            //全网对比
            Query query = MatchQuery.of(t -> t.field("str").query(content).minimumShouldMatch("45%"))._toQuery();
            allQueryBuilder.must(query);

            SearchResponse<EsServerEntity> response = esClient.search(s -> s
                            .index(IndexConfig.PUB_TEXT_INDEX)
                            .fields(Arrays.asList(
                                    FieldAndFormat.of(builder -> builder.field("file_id")),
                                    FieldAndFormat.of(builder -> builder.field("sentence")),
                                    FieldAndFormat.of(builder -> builder.field("database_type")),
                                    FieldAndFormat.of(builder -> builder.field("str")),
                                    FieldAndFormat.of(builder -> builder.field("sub_project")),
                                    FieldAndFormat.of(builder -> builder.field("table_id"))))
                            .from(0)
                            .size(5)
                            .highlight(h -> h.preTags("<span style=\"color:red\">").postTags("</span>").fields("str", highlightFieldBuilder -> highlightFieldBuilder))
                            .query(allQueryBuilder.build()._toQuery()),
                    EsServerEntity.class
            );
            List<Hit<EsServerEntity>> hits = response.hits().hits();
            List<EsServerEntity> resEsServerEntity = new ArrayList<>();
            for (Hit<EsServerEntity> hit : hits) {
                EsServerEntity source1 = hit.source();
                Map<String, List<String>> highlight = hit.highlight();
                source1.setHighlight(highlight);
                source1.setESid(hit.id());
                resEsServerEntity.add(source1);
            }
            res = Collections.singletonList(resEsServerEntity);
        }
        // 0是全网 1是自定义2文件比对


        return res;
    }


    @SneakyThrows
    public String esBackDataPreNext(String dataType, Integer sentence, String subProject, String file_id, String table_no) {

        BoolQuery of = BoolQuery.of((boolQueryBuilder -> boolQueryBuilder
                .must(queryBuilder2 -> queryBuilder2
                        .term(termBuilder -> termBuilder.field("sub_project.keyword").value(subProject)))
                .must(queryBuilder2 -> queryBuilder2
                        .term(termBuilder -> termBuilder.field("sentence").value(sentence)))
                .must(queryBuilder2 -> queryBuilder2
                        .term(termBuilder -> termBuilder.field("file_id").value(Integer.parseInt(file_id))))
                .must(queryBuilder2 -> queryBuilder2
                        .term(termBuilder -> termBuilder.field("table_id").value(Integer.parseInt(table_no))))
                .must(queryBuilder2 -> queryBuilder2
                        .term(termBuilder -> termBuilder.field("database_type").value(Integer.parseInt(dataType))))

        ));
        SearchRequest.Builder builder = new SearchRequest.Builder();
        SearchRequest searchRequest = builder.query(of._toQuery()).build();
//        printEsBySearchRequest(searchRequest);
        SearchResponse<JSONObject> response = esClient.search(searchRequest
                , JSONObject.class);

        List<Hit<JSONObject>> hits = response.hits().hits();
        if (hits.size() > 0) {
            return hits.get(0).source().getString("str");
        }
        return "";
    }

    public BackMatchEntity findTableInfo(Integer tableId, Integer fileId, String matchStr, String isManual) {
        // 进行匹配原始标题进行查表
        Db use = Db.use(DSFactory.get("paper_article"));
        boolean is = Boolean.valueOf(isManual);
        if (!is) {
            if (tableId > 0) {
                String table = "ncbi_pdf_to_txt_101".replace("101", tableId + "");
                Entity entity = DbSearchUtil.backEntity(use, table, fileId);
                if (entity != null) {
                    Integer file_id = entity.getInt("file_id");
                    if (StringUtil.isNotNull(file_id)) {
                        String URL = "https://pm.yuntsg.com/utils/getpuinfo?type=1&q=123";
                        String s = HttpUtil.get(URL.replace("123", file_id + ""));
                        if (StringUtil.isNotNull(s)) {
                            JSONObject jsonObject = JSONObject.parseObject(s);
                            JSONObject data = jsonObject.getJSONObject("data");
                            String code = jsonObject.getString("code");
                            if (code.equals("0")) {
                                PmUtEntity pmUtEntity = data.toJavaObject(PmUtEntity.class);
                                BackMatchEntity ba = new BackMatchEntity();
                                ba.setType("pm");
                                ba.setTitle(pmUtEntity.getTitle());
                                ba.setYear(pmUtEntity.getYear());
                                ba.setAu(pmUtEntity.getAu());
                                ba.setJour(pmUtEntity.getJour());
                                ba.setMatchStr(matchStr);
                                ba.setKey(file_id + "");
                                ba.setDoi(pmUtEntity.getDoi());
                                return ba;
                            }
                        }
                    }
                } else {
                    return null;
                }
            }
        }
        return null;
    }


}
